package com.hsjk.szwj.module.pay.controller.app.division;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hsjk.szwj.framework.common.constant.CommonConstant;
import com.hsjk.szwj.framework.common.exception.ServiceException;
import com.hsjk.szwj.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.hsjk.szwj.module.pay.constant.PayOrderConstant;
import com.hsjk.szwj.module.pay.constant.PayOrderDivisionConstant;
import com.hsjk.szwj.module.pay.controller.PayApiController;
import com.hsjk.szwj.module.pay.controller.app.division.vo.PayOrderDivisionExecReqVO;
import com.hsjk.szwj.module.pay.controller.app.division.vo.PayOrderDivisionExecRespVO;
import com.hsjk.szwj.module.pay.dal.dataobject.CommonPayResult;
import com.hsjk.szwj.module.pay.dal.dataobject.config.ChannelRetMsg;
import com.hsjk.szwj.module.pay.dal.dataobject.config.MchAppConfigContext;
import com.hsjk.szwj.module.pay.dal.dataobject.config.PayOrderDivisionMQ;
import com.hsjk.szwj.module.pay.dal.dataobject.division.MchDivisionReceiverDO;
import com.hsjk.szwj.module.pay.dal.dataobject.division.MchDivisionReceiverGroupDO;
import com.hsjk.szwj.module.pay.dal.dataobject.order.PayOrderDO;
import com.hsjk.szwj.module.pay.dal.dataobject.system.MchAppDO;
import com.hsjk.szwj.module.pay.dal.dataobject.system.MchInfoDO;
import com.hsjk.szwj.module.pay.service.ConfigContextQueryService;
import com.hsjk.szwj.module.pay.service.IMchAppService;
import com.hsjk.szwj.module.pay.service.IMchInfoService;
import com.hsjk.szwj.module.pay.service.MchDivisionReceiverGroupService;
import com.hsjk.szwj.module.pay.service.MchDivisionReceiverService;
import com.hsjk.szwj.module.pay.service.PayInterfaceDefineService;
import com.hsjk.szwj.module.pay.service.PayOrderDivisionProcessService;
import com.hsjk.szwj.module.pay.service.PayOrderService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author chenjiawei
 * @desc
 * @Date 2023/08/25 01:16
 **/
@Tag(name = "应用端 - 分账相关接口")
@RestController
@RequestMapping("/division")
@Validated
@Slf4j
public class PayOrderDivisionExecController extends PayApiController {
    @Resource
    private ConfigContextQueryService configContextQueryService;
    @Resource
    private PayOrderService payOrderService;
    @Resource
    private MchDivisionReceiverService mchDivisionReceiverService;
    @Resource
    private MchDivisionReceiverGroupService mchDivisionReceiverGroupService;
    @Resource
    private PayOrderDivisionProcessService payOrderDivisionProcessService;
    @Resource
    private IMchInfoService mchInfoService;
    @Resource
    private PayInterfaceDefineService payInterfaceDefineService;

    @Resource
    private IMchAppService mchAppService;

    /**
     * 分账执行
     **/
    @PostMapping("/exec")
    public CommonPayResult exec(@RequestBody @Validated PayOrderDivisionExecReqVO bizRQ) {
        try {

            if (ObjectUtil.isNull(bizRQ.getMchOrderId())
                    && ObjectUtil.isNull(bizRQ.getPayOrderId())) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "mchOrderNo 和 payOrderId不能同时为空");
            }
            MchInfoDO mchInfoDO = mchInfoService.getMchInfoByTenant();
            MchAppDO mchAppDO = mchAppService.getByTenant();
            PayOrderDO payOrder = payOrderService.queryMchOrder(mchInfoDO.getId(),
                    bizRQ.getPayOrderId(), bizRQ.getMchOrderId());
            if (payOrder == null) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "订单不存在");
            }

            if (payOrder.getState() != PayOrderConstant.STATE_SUCCESS
                    || payOrder.getDivisionState() != PayOrderConstant.DIVISION_STATE_UNHAPPEN
                    || payOrder.getDivisionMode() == PayOrderConstant.DIVISION_MODE_FORBID) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "当前订单状态不支持分账");
            }

            List<PayOrderDivisionMQ.CustomerDivisionReceiver> receiverList = null;

            //不使用默认分组， 需要转换每个账号信息
            if (!CommonConstant.YES.equals(bizRQ.getUseSysAutoDivisionReceivers())
                    && !StringUtils.isEmpty(bizRQ.getReceivers())) {
                receiverList = JSONUtil.toList(bizRQ.getReceivers(),
                        PayOrderDivisionMQ.CustomerDivisionReceiver.class);
            }
            String ifCode = payInterfaceDefineService.getCodeById(payOrder.getIfId());
            // 验证账号是否合法
            this.checkReceiverList(receiverList, ifCode,
                    mchInfoDO.getId(), mchAppDO.getId());

            // 商户配置信息
            MchAppConfigContext mchAppConfigContext =
                    configContextQueryService.queryMchInfoAndAppInfo(mchInfoDO.getId(),
                            mchAppDO.getId());
            if (mchAppConfigContext == null) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "获取商户应用信息失败");
            }

            //处理分账请求
            ChannelRetMsg channelRetMsg =
                    payOrderDivisionProcessService
                            .processPayOrderDivision(payOrder.getId(),
                                    bizRQ.getUseSysAutoDivisionReceivers(),
                                    receiverList, false);

            PayOrderDivisionExecRespVO bizRS = new PayOrderDivisionExecRespVO();
            bizRS.setState(channelRetMsg.getChannelState()
                    == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS
                    ? PayOrderDivisionConstant.STATE_SUCCESS :
                    PayOrderDivisionConstant.STATE_FAIL);
            bizRS.setChannelBatchOrderId(channelRetMsg.getChannelOrderId());
            bizRS.setErrCode(channelRetMsg.getChannelErrCode());
            bizRS.setErrMsg(channelRetMsg.getChannelErrMsg());

            return CommonPayResult.okWithSign(bizRS, mchAppConfigContext.getMchApp()
                    .getAppSecret());

        } catch (ServiceException e) {
            return CommonPayResult.error(e.getMessage());

        } catch (Exception e) {
            log.error("系统异常：{}", e);
            return CommonPayResult.error("系统异常");
        }
    }

    /**
     * 检验账号是否合法
     **/
    private void checkReceiverList(List<PayOrderDivisionMQ.CustomerDivisionReceiver> receiverList,
                                   String ifCode, Long mchId, Long appId) {

        if (receiverList == null || receiverList.isEmpty()) {
            return;
        }

        Set<Long> receiverIdSet = new HashSet<>();
        Set<Long> receiverGroupIdSet = new HashSet<>();

        for (PayOrderDivisionMQ.CustomerDivisionReceiver receiver : receiverList) {

            if (receiver.getReceiverId() != null) {
                receiverIdSet.add(receiver.getReceiverId());
            }

            if (receiver.getReceiverGroupId() != null) {
                receiverGroupIdSet.add(receiver.getReceiverGroupId());
            }

            if (receiver.getReceiverId() == null && receiver.getReceiverGroupId() == null) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "分账用户组： receiverId 和 与receiverGroupId 必填一项");
            }

            if (receiver.getDivisionProfit() != null) {

                if (receiver.getDivisionProfit().compareTo(BigDecimal.ZERO) < 0) {
                    throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                            "分账用户receiverId=[" + (receiver.getReceiverId() == null ? "" : receiver.getReceiverId()) + "]," +
                                    "receiverGroupId=[" + (receiver.getReceiverGroupId() == null ? "" : receiver.getReceiverGroupId()) + "] 分账比例不得小于0%");
                }

                if (receiver.getDivisionProfit().compareTo(BigDecimal.ONE) > 0) {
                    throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                            "分账用户receiverId=[" + (receiver.getReceiverId() == null ? "" : receiver.getReceiverId()) + "]," +
                                    "receiverGroupId=[" + (receiver.getReceiverGroupId() == null ? "" : receiver.getReceiverGroupId()) + "] 分账比例不得高于100%");
                }
            }
        }
        MchInfoDO mchInfoDO = mchInfoService.getMchInfoById(mchId);
        if (!receiverIdSet.isEmpty()) {
            long receiverCount = mchDivisionReceiverService.count(
                    new LambdaQueryWrapper<MchDivisionReceiverDO>()
                            .in(MchDivisionReceiverDO::getId, receiverIdSet)
                            .eq(MchDivisionReceiverDO::getMchId, mchInfoDO.getId())
                            .eq(MchDivisionReceiverDO::getAppId, appId)
                            .eq(MchDivisionReceiverDO::getIfCode, ifCode)
                            .eq(MchDivisionReceiverDO::getState, CommonConstant.YES)
            );

            if (receiverCount != receiverIdSet.size()) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "分账[用户]中包含不存在或渠道不可用账号，请更改");
            }
        }

        if (!receiverGroupIdSet.isEmpty()) {

            long receiverGroupCount =
                    mchDivisionReceiverGroupService.count(new LambdaQueryWrapper<MchDivisionReceiverGroupDO>()
                            .in(MchDivisionReceiverGroupDO::getId, receiverGroupIdSet)
                            .eq(MchDivisionReceiverGroupDO::getMchNo, mchInfoDO.getId())
                    );

            if (receiverGroupCount != receiverGroupIdSet.size()) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "分账[账号组]中包含不存在或不可用组，请更改");
            }
        }

    }
}
